package com.zzh.interview.aop;

import com.jd.platform.hotkey.client.callback.JdHotKeyStore;
import com.zzh.interview.annotation.AuthCheck;
import com.zzh.interview.annotation.HotKeyCache;
import com.zzh.interview.annotation.TestHot;
import com.zzh.interview.common.BaseResponse;
import com.zzh.interview.common.ErrorCode;
import com.zzh.interview.common.ResultUtils;
import com.zzh.interview.exception.BusinessException;
import com.zzh.interview.exception.ThrowUtils;
import com.zzh.interview.model.dto.TestRequest;
import com.zzh.interview.model.dto.questionBank.QuestionBankQueryRequest;
import com.zzh.interview.model.entity.User;
import com.zzh.interview.model.enums.UserRoleEnum;
import com.zzh.interview.model.vo.QuestionBankVO;
import com.zzh.interview.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 权限校验 AOP
 *
 * @author <a href="https://gitee.com/zzhpalus">zzhKing</a>
 * @from <a href="https://gitee.com/zzhpalus">致力于学习</a>
 */
@Aspect
@Component
@Slf4j
public class AuthInterceptor {

    @Resource
    private UserService userService;

    /**
     * 执行拦截
     * 针对你加了注解的接口方法进行权限校验，如果出现了权限不足的情况，则会抛出异常，并返回错误码
     * 获取当前用户信息角色然后进行校验！
     * @param joinPoint
     * @param authCheck
     * @return
     */
//    @Around("@annotation(authCheck)")
//    public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {
//        String mustRole = authCheck.mustRole();
//        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
//        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
//        // 当前登录用户
//        User loginUser = userService.getCurrentUser(request);
//        UserRoleEnum mustRoleEnum = UserRoleEnum.getEnumByValue(mustRole);
//        // 不需要权限，放行
//        if (mustRoleEnum == null) {
//            return joinPoint.proceed();
//        }
//        // 必须有该权限才通过
//        UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(loginUser.getUserRole());
//        if (userRoleEnum == null) {
//            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
//        }
//        // 如果被封号，直接拒绝
//        if (UserRoleEnum.BAN.equals(userRoleEnum)) {
//            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
//        }
//        // 必须有管理员权限
//        if (UserRoleEnum.ADMIN.equals(mustRoleEnum)) {
//            // 用户没有管理员权限，拒绝
//            if (!UserRoleEnum.ADMIN.equals(userRoleEnum)) {
//                throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
//            }
//        }
//        // 通过权限校验，放行
//        return joinPoint.proceed();
//    }


    /**
     * 执行拦截
     * 针对你加了注解的接口方法进行权限校验，如果出现了权限不足的情况，则会抛出异常，并返回错误码
     * 获取当前用户信息角色然后进行校验！
     * @param joinPoint
     * @param hotKeyCache
     * @return
     */
    @Around("@annotation(hotKeyCache)")
    public Object doInterceptorHotKey(ProceedingJoinPoint joinPoint, HotKeyCache hotKeyCache) throws Throwable {
        // 获取当前请求参数 暂时只支持一种参数
        Object arg = joinPoint.getArgs()[0];
        ThrowUtils.throwIf(arg == null, ErrorCode.PARAMS_ERROR);
        String key = "";
        if (arg instanceof QuestionBankQueryRequest) {
            QuestionBankQueryRequest questionBankQueryRequest = (QuestionBankQueryRequest) arg;
            Long id = questionBankQueryRequest.getId();
            ThrowUtils.throwIf(id <= 0, ErrorCode.PARAMS_ERROR);

            // 生成 key 前缀 + 题库的 id标识 / 其他的id
            key = String.format("%s_%s", hotKeyCache.keyPrefix(), id);
        }else if (arg instanceof TestRequest){
            TestRequest testRequest = (TestRequest) arg;
            String name = testRequest.getName();
            ThrowUtils.throwIf(name == null || name.isEmpty() , ErrorCode.PARAMS_ERROR);

            // 生成 key 前缀 + 题库的 id标识 / 其他的id
            key = String.format("%s_%s", hotKeyCache.keyPrefix(), name);
        }

        // 如果是热 key
        if (JdHotKeyStore.isHotKey(key)) {
            // 从本地缓存中获取缓存值
            log.info("命中热 key，从缓存中获取缓存值");
            Object cachedQuestionBankVO = JdHotKeyStore.get(key);
            if (cachedQuestionBankVO != null) {
                // 如果缓存中有值，直接返回缓存的值
                return ResultUtils.success(cachedQuestionBankVO);
            }
        }
        // 缓存中没有值，执行业务逻辑 =》数据库查询并且缓存
        BaseResponse successData =  (BaseResponse)joinPoint.proceed();

        log.info("执行完毕。。准备检查是否需要缓存");

        // 设置本地缓存（如果不是热 key，这个方法不会设置缓存）
        Object data = successData.getData();
        JdHotKeyStore.smartSet(key, data);

        // 获取封装类
        return successData;
    }


    /**
     * 执行拦截
     * 针对你加了注解的接口方法进行权限校验，如果出现了权限不足的情况，则会抛出异常，并返回错误码
     * 获取当前用户信息角色然后进行校验！
     * @param joinPoint
     * @param testHot
     * @return
     */
    @Around("@annotation(testHot)")
    public Object doInterceptorTestHot(ProceedingJoinPoint joinPoint, TestHot testHot) throws Throwable {
        // 获取当前请求参数 暂时只支持一种参数
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0){
            log.info("参数：{}", args[0]);
            log.info("参数类型：{}", args[0].getClass());
        }else {
            log.info("无参数");
        }
        return joinPoint.proceed();
    }
}

